package com.practice.concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockMain {

	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		MyReentrantLock lock = new MyReentrantLock();
		for (int i = 0; i < 10; i++) {
			service.submit(new ReentrantLockCommand(i, lock));
		}
		service.shutdown();
	}
}

class ReentrantLockCommand implements Runnable {
	MyReentrantLock lock;
	private int id;

	public ReentrantLockCommand(int id, MyReentrantLock lock) {
		this.id = id;
		this.lock = lock;
	}

	@Override
	public void run() {
		lock.print(id);
	}
}

class MyReentrantLock {
	private ReentrantLock lock = new ReentrantLock();

	public void print(int id) {
		try {
			lock.lock();
			System.out.println(id + " gets lock");
			System.out.println(id + " hold lock count: " + lock.getHoldCount());
			
			printInner(id);
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			lock.unlock();
			System.out.println(id + " release lock");
			System.out.println(id + " hold lock count: " + lock.getHoldCount());
		}
	}

	public void printInner(int id) {
		try {
			lock.lock();
			System.out.println(id + " gets lock in inner level");
			System.out.println(id + " hold lock count: " + lock.getHoldCount());
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			lock.unlock();
			System.out.println(id + " release lock in inner level");
			System.out.println(id + " hold lock count: " + lock.getHoldCount());
		}
	}
}